了解如何在 scikit-learn 中创建自定义评估器以扩展其功能并实现您自己的机器学习算法。本指南涵盖从基础到高级技术的所有内容。
Python Scikit-learn 自定义评估器:算法实现的全面指南
Scikit-learn 是一个强大且广泛使用的 Python 机器学习库。 虽然它提供了大量的预构建算法,但在某些情况下,您需要实现自己的自定义算法。 幸运的是,scikit-learn 提供了一个灵活的框架,用于创建自定义评估器,允许您将您的算法无缝集成到 scikit-learn 生态系统中。 本全面指南将引导您完成构建自定义评估器的过程,从了解基础知识到实现高级技术。 我们还将探讨现实世界的例子,以说明自定义评估器的实际应用。
为什么要创建自定义评估器?
在深入研究实现细节之前,让我们了解一下您可能想要创建自定义评估器的原因:
- 实现新颖的算法: Scikit-learn 并不涵盖所有可能的机器学习算法。 如果您开发了一种新算法或想实现一篇研究论文,那么创建自定义评估器是最佳选择。
- 自定义现有算法: 您可能想修改现有的 scikit-learn 算法以更好地满足您的特定需求。 自定义评估器允许您扩展或调整现有功能。
- 与外部库集成: 您可能想使用其他 Python 库中的算法,这些算法与 scikit-learn 不直接兼容。 自定义评估器提供了这些库与 scikit-learn 的 API 之间的桥梁。
- 提高代码重用性: 通过将您的算法封装到自定义评估器中,您可以轻松地在不同的项目中重用它并与他人共享它。
- 增强管道集成: 自定义评估器与 scikit-learn 的管道无缝集成,使您能够构建复杂的机器学习工作流程。
了解 Scikit-learn 评估器的基础知识
从本质上讲,scikit-learn 评估器是一个 Python 类,它实现了 fit 和 predict 方法(有时还有其他方法,如 transform 或 fit_transform)。 这些方法定义了评估器在训练和预测期间的行为。 有两种主要的评估器类型:
- 转换器: 这些评估器将数据从一种格式转换为另一种格式。 示例包括
StandardScaler、PCA和OneHotEncoder。 它们通常实现fit和transform方法。 - 模型(预测器): 这些评估器从数据中学习一个模型,并使用它进行预测。 示例包括
LinearRegression、DecisionTreeClassifier和KMeans。 它们通常实现fit和predict方法。
这两种类型的评估器共享一个公共 API,允许您在管道和其他 scikit-learn 工具中互换使用它们。
创建简单的自定义转换器
让我们从一个简单的自定义转换器示例开始。 此转换器将每个特征按一个常数因子进行缩放。 此转换器类似于 `StandardScaler`,但更简单,并允许指定自定义缩放因子。
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np
class FeatureScaler(BaseEstimator, TransformerMixin):
def __init__(self, factor=1.0):
self.factor = factor
def fit(self, X, y=None):
# No fitting needed for this transformer
return self
def transform(self, X):
return X * self.factor
以下是代码的分解:
- 继承: 我们从
BaseEstimator和TransformerMixin继承。BaseEstimator提供了基本功能,如get_params和set_params,而TransformerMixin提供了fit_transform的默认实现(它调用fit然后调用transform)。 __init__: 这是构造函数。 它将缩放因子作为参数,并将其存储在self.factor属性中。 在构造函数中定义评估器的参数非常重要。fit: 调用此方法将转换器拟合到数据。 在这种情况下,我们不需要从数据中学习任何东西,因此我们只需返回self。 对于转换器,通常不使用y参数,但为了与 scikit-learn API 兼容,需要它。transform: 调用此方法将数据转换为。 我们只需将每个特征乘以缩放因子。
现在,让我们看看如何使用这个自定义转换器:
# Example Usage
from sklearn.pipeline import Pipeline
X = np.array([[1, 2], [3, 4], [5, 6]])
# Create a FeatureScaler with a factor of 2
scaler = FeatureScaler(factor=2.0)
# Transform the data
X_transformed = scaler.transform(X)
print(X_transformed)
# Output:
# [[ 2. 4.]
# [ 6. 8.]
# [10. 12.]]
# Using in a pipeline
pipe = Pipeline([('scaler', FeatureScaler(factor=3.0))])
X_transformed_pipeline = pipe.fit_transform(X)
print(X_transformed_pipeline)
# Output:
# [[ 3. 6.]
# [ 9. 12.]
# [15. 18.]]
创建简单的自定义模型(预测器)
接下来,让我们创建一个简单的自定义模型。 此模型将预测所有未来预测的训练数据的均值。 虽然它不是特别有用,但它演示了自定义预测器的基本结构。
from sklearn.base import BaseEstimator, RegressorMixin
import numpy as np
class MeanPredictor(BaseEstimator, RegressorMixin):
def __init__(self):
self.mean_ = None
def fit(self, X, y):
self.mean_ = np.mean(y)
return self
def predict(self, X):
return np.full(X.shape[0], self.mean_)
以下是代码的分解:
- 继承: 我们从
BaseEstimator和RegressorMixin继承。RegressorMixin提供了与回归相关的方法的默认实现(尽管在此示例中我们未使用它们)。 __init__: 我们将self.mean_初始化为None。 此属性将存储拟合后的目标变量的均值。fit: 此方法计算目标变量y的均值并将其存储在self.mean_中。predict: 此方法返回一个与输入X长度相同的数组,其中每个元素等于存储的均值。
现在,让我们看看如何使用这个自定义模型:
# Example Usage
X = np.array([[1], [2], [3]])
y = np.array([10, 20, 30])
# Create a MeanPredictor
predictor = MeanPredictor()
# Fit the model
predictor.fit(X, y)
# Predict on new data
X_new = np.array([[4], [5], [6]])
y_pred = predictor.predict(X_new)
print(y_pred)
# Output:
# [20. 20. 20.]
实现参数验证
验证传递给自定义评估器的参数至关重要。 这有助于防止意外行为,并为用户提供信息性错误消息。 您可以使用 sklearn.utils.estimator_checks 中的 check_estimator 函数自动测试您的评估器是否符合一组常见检查。
首先,让我们修改 FeatureScaler 以包含参数验证:
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils import validation
class FeatureScaler(BaseEstimator, TransformerMixin):
def __init__(self, factor=1.0):
self.factor = factor
def fit(self, X, y=None):
# Validate the input
self.factor = validation.check_scalar(
self.factor,
'factor',
target_type=float,
min_val=0.0,
include_boundaries=True
)
return self
def transform(self, X):
validation.check_is_fitted(self)
X = validation.check_array(X)
return X * self.factor
以下是我们添加的内容:
validation.check_scalar: 我们在fit方法中使用此函数来验证factor参数是否为大于或等于 0 的 float。validation.check_is_fitted: 我们在transform方法中使用此函数来确保在转换数据之前已拟合评估器。validation.check_array: 我们使用此函数来验证输入X是否为有效数组。
现在,让我们使用 check_estimator 来测试我们的评估器:
from sklearn.utils.estimator_checks import check_estimator
# Perform checks
check_estimator(FeatureScaler)
如果您的评估器有任何问题(例如,不正确的参数类型或缺少方法),check_estimator 将引发错误。 这是一个强大的工具,可确保您的自定义评估器符合 scikit-learn API。
使用 GridSearchCV 处理超参数
创建自定义评估器的主要好处之一是您可以使用它们与 scikit-learn 的超参数调整工具(如 GridSearchCV 和 RandomizedSearchCV)一起使用。 要使您的评估器与这些工具兼容,您需要确保其参数可访问和可修改。 这通常会由于 `BaseEstimator` 类而自动处理。
让我们用 FeatureScaler 演示这一点。 我们将使用 GridSearchCV 找到最佳缩放因子:
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import Pipeline
import numpy as np
# Create a pipeline with the FeatureScaler
pipe = Pipeline([('scaler', FeatureScaler())])
# Define the parameter grid
param_grid = {'scaler__factor': [0.5, 1.0, 1.5, 2.0]}
# Create a GridSearchCV object
grid_search = GridSearchCV(pipe, param_grid, cv=3, scoring='r2') # Using R^2 as an example scoring metric.
# Generate some sample data
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
y = np.array([2, 4, 6, 8, 10])
# Fit the grid search
grid_search.fit(X, y)
# Print the best parameters and score
print("Best parameters:", grid_search.best_params_)
print("Best score:", grid_search.best_score_)
在此示例中,我们定义了一个参数网格,该网格指定了要搜索的 factor 参数的值。 然后,GridSearchCV 将使用每种参数组合评估管道,并返回最佳性能集。 请注意命名约定 `scaler__factor`,用于访问管道阶段内的参数。
高级技术:处理复杂数据类型和缺失值
自定义评估器也可用于处理复杂数据类型和缺失值。 例如,您可能想创建一个转换器,该转换器使用特定于域的策略来插补缺失值,或者将分类特征转换为数值表示。 关键是仔细考虑数据的特定要求,并在 fit 和 transform 方法中实现适当的逻辑。
让我们考虑一个使用中位数插补缺失值的自定义转换器的示例:
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np
class MedianImputer(BaseEstimator, TransformerMixin):
def __init__(self):
self.median_ = None
def fit(self, X, y=None):
# Calculate the median for each column
self.median_ = np.nanmedian(X, axis=0)
return self
def transform(self, X):
# Impute missing values with the median
X_imputed = np.where(np.isnan(X), self.median_, X)
return X_imputed
在此示例中,fit 方法计算输入数据中每一列的中位数,忽略缺失值 (np.nan)。 然后,transform 方法将输入数据中任何缺失值替换为相应的中位数。
以下是如何使用它:
# Example Usage
X = np.array([[1, 2, np.nan], [3, np.nan, 5], [np.nan, 4, 6]])
# Create a MedianImputer
imputer = MedianImputer()
# Fit the imputer
imputer.fit(X)
# Transform the data
X_imputed = imputer.transform(X)
print(X_imputed)
# Output:
# [[1. 2. 5.5]
# [3. 4. 5. ]
# [2. 4. 6. ]]
实际示例和用例
让我们探讨一些自定义评估器可能特别有用的实际示例:
- 时间序列特征工程: 您可能想创建一个自定义转换器,该转换器从时间序列数据中提取特征,例如滚动统计数据或滞后值。 例如,在金融市场中,您可以创建一个评估器,该评估器计算特定窗口内股票价格的移动平均值和标准差。 然后,此评估器可在管道中使用以预测未来的股票价格。 窗口大小可以是
GridSearchCV调整的超参数。 - 自然语言处理 (NLP): 您可以创建一个自定义转换器,该转换器使用 scikit-learn 中不可直接使用的技术执行文本清理或特征提取。 例如,您可能想实现一个针对特定语言或域定制的自定义词干分析器或词形还原器。 您还可以在自定义评估器中集成外部库,如 NLTK 或 spaCy。
- 图像处理: 您可能想创建一个自定义转换器,该转换器在将图像馈送到机器学习模型之前应用特定的图像处理操作,例如过滤或边缘检测。 这可能涉及与 OpenCV 或 scikit-image 等库集成。 例如,评估器可能在训练模型以检测肿瘤之前,对医学图像的亮度和对比度进行归一化。
- 推荐系统: 您可以构建一个自定义评估器,该评估器实现协同过滤算法,例如矩阵分解,以生成个性化推荐。 这可能涉及与 Surprise 或 implicit 等库集成。 例如,电影推荐系统可能使用自定义评估器根据用户过去的偏好和其他用户的评分来预测用户评分。
- 地理空间数据分析: 创建自定义转换器以处理位置数据。 这可能涉及计算点之间的距离、执行空间连接或从地理形状中提取特征。 例如,您可以计算每个客户与最近商店位置的距离,从而为营销策略提供信息。
创建自定义评估器的最佳实践
为了确保您的自定义评估器具有鲁棒性、可维护性并与 scikit-learn 兼容,请遵循以下最佳实践:
- 从
BaseEstimator和适当的 Mixin 继承: 这提供了基本功能并确保与 scikit-learn 的 API 兼容。 - 实现
__init__、fit和transform(或predict): 这些方法是您的评估器的核心。 - 验证输入参数: 使用
sklearn.utils.validation验证传递给您的评估器的参数。 - 适当地处理缺失值: 决定您的评估器应如何处理缺失值并实现适当的逻辑。
- 记录您的代码: 为您的评估器提供清晰简洁的文档,包括其目的、参数和用法。 使用符合 NumPy/SciPy 约定的文档字符串以保持一致性。
- 测试您的代码: 使用
sklearn.utils.estimator_checks根据一组常见检查来测试您的评估器。 此外,编写单元测试以验证您的评估器是否正常运行。 - 遵循 Scikit-learn 的约定: 遵守 scikit-learn 的编码风格和 API 约定,以确保一致性和可维护性。
- 考虑使用装饰器: 适当情况下,使用来自 `typing-extensions` 等库的装饰器(如
@validate_arguments)来简化参数验证。
结论
在 scikit-learn 中创建自定义评估器允许您扩展其功能并实现您自己的机器学习算法。 通过遵循本指南中概述的准则和最佳实践,您可以创建与 scikit-learn 生态系统无缝集成的、鲁棒、可维护和可重用的评估器。 无论您是实现新颖的算法、自定义现有算法还是与外部库集成,自定义评估器都提供了一个强大的工具,用于解决复杂的机器学习问题。
请记住彻底测试和记录您的自定义评估器,以确保其质量和可用性。 通过对 scikit-learn API 的扎实理解和一点创造力,您可以利用自定义评估器来构建适合您特定需求的复杂机器学习解决方案。 祝你好运!